package p2p

import (
	"bufio"
	"encoding/json"
	"fmt"
	"osiris/core/conversion"
	"osiris/dto"
	"osiris/logger"
	"sync"

	"github.com/libp2p/go-libp2p/core/network"
	peer "github.com/libp2p/go-libp2p/core/peer"
	"github.com/libp2p/go-libp2p/core/protocol"
)

// DiscoveryProtocol 主动节点发现
type DiscoveryProtocol struct{}

func (protocol DiscoveryProtocol) protocolName() protocol.ID {
	return "/p2p/discovery"
}

func (protocol DiscoveryProtocol) openStream(peerID peer.ID, jsonStr string, wg *sync.WaitGroup) {
	//TODO
}

func (protocol DiscoveryProtocol) handleStream(s network.Stream) {
	logger.Println("Got a new stream " + protocol.protocolName())
	logger.Info(map[string]interface{}{fmt.Sprintf("[p2p] [Handle Stream %s]", protocol.protocolName()): "Got a new stream "})

	rw := bufio.NewReadWriter(bufio.NewReader(s), bufio.NewWriter(s))

	go func() {
		var returnPeerDto dto.PeerDto
		errorOccured := true
		//最后返回查询结果
		defer func() {
			//流程中出现错误的话返回dto.CODE_INTERNAL_ERROR
			if errorOccured {
				returnPeerDto = dto.PeerDto{
					BaseDto: dto.BaseDto{
						Code: dto.CODE_INTERNAL_ERROR,
					},
				}
			}

			returnPeerDtoJsonBytes, err := json.Marshal(returnPeerDto)
			if err != nil {
				//序列化出错时直接主动关闭流，不让另外一边等
				logger.Error(map[string]interface{}{fmt.Sprintf("[p2p] [Handle Stream %s] returnPeerDto marshal",protocol.protocolName()): err})
				s.Close()
				return
			}
			rw.WriteString(string(returnPeerDtoJsonBytes))
			rw.Flush()
			//TODO 等待对方节点关闭网络流
		}()

		//处理查询节点发来的PeerDto
		str, err1 := rw.ReadString('\n')
		if err1 != nil {
			logger.Error(map[string]interface{}{fmt.Sprintf("[p2p] [Handle Stream %s] read string", protocol.protocolName()): err1})
			return
		}
		var peerDto dto.PeerDto
		if err2 := json.Unmarshal([]byte(str), &peerDto); err2 != nil {
			logger.Error(map[string]interface{}{fmt.Sprintf("[p2p] [Handle Stream %s] PeerDto unmarshal", protocol.protocolName()): err2})
			return
		}

		//PeerIDStr转Peer.ID
		targetPeerID, err3 := conversion.StrToPeerID(peerDto.TargetPeerID)
		if err3 != nil {
			logger.Error(map[string]interface{}{fmt.Sprintf("[p2p] [Handle Stream %s] Generate peer.ID", protocol.protocolName()): err3})
			return
		}
		//查询peerStore
		addrs := ha.Peerstore().Addrs(targetPeerID)
		//PeerStore里查不到peerID对应的addrs
		if len(addrs) == 0 {
			logger.Info(map[string]interface{}{
				fmt.Sprintf("[p2p] [Handle Stream %s] query Ha.PeerStore", protocol.protocolName()): "can not find addrs of peerID " + peerDto.TargetPeerID,
			})
			returnPeerDto = dto.PeerDto{
				BaseDto: dto.BaseDto{
					Code: dto.CODE_NODE_NOT_STORED,
				},
				TargetPeerID:     peerDto.TargetPeerID,
				SenderPeerID:     ha.ID().String(),
				SenderMultiaddrs: conversion.MultiaddrsToStrings(ha.Addrs()),
			}
		} else {
			//PeerStore里有peerID对应的addrs
			logger.Info(map[string]interface{}{
				fmt.Sprintf("[p2p] [Handle Stream %s] query Ha.PeerStore",protocol.protocolName()): "find addrs of peerID " + peerDto.TargetPeerID,
			})
			returnPeerDto = dto.PeerDto{
				BaseDto: dto.BaseDto{
					Code: dto.CODE_NODE_STORED,
				},
				TargetPeerID:     peerDto.TargetPeerID,
				TargetMultiaddrs: conversion.MultiaddrsToStrings(addrs),
				SenderPeerID:     ha.ID().String(),
				SenderMultiaddrs: conversion.MultiaddrsToStrings(ha.Addrs()),
			}
		}
		//整个流程没出错，即将进入defer
		errorOccured = false
	}()
}
